﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Pfz.DynamicObjects;
using Pfz.Remoting.Internal;

namespace Pfz.Remoting.Instructions
{
	internal sealed class InstructionGetProperty:
		Instruction
	{
		public long ObjectId;
		public PropertyInfo PropertyInfo;

		[SuppressMessage("Microsoft.Usage", "CA2219:DoNotRaiseExceptionsInExceptionClauses")]
		public override void Run(RemotingClient client, _ThreadData threadData)
		{
			threadData._Action
			(
				PropertyInfo.GetGetMethod(),
				null,
				() =>
				{
					var obj = client._objectsUsedByTheOtherSide.Get(ObjectId);

					InvokeProperty_EventArgs args = null;
					EventHandler<InvokeProperty_EventArgs> before = null;
					EventHandler<InvokeProperty_EventArgs> after = null;
					var events = client._parameters._invokePropertyGetEvents;

					if (events != null)
					{
						before = events._beforeInvoke;
						after = events._afterInvoke;

						if (before != null || after != null)
						{
							args = new InvokeProperty_EventArgs();
							args.PropertyInfo = PropertyInfo;
							args.Target = obj;
						}
					}

					object result = null;
					try
					{
						if (before != null)
						{
							before(this, args);
							if (!args.CanInvoke)
								return args.Value;
						}

						var fastProperty = threadData._GetPropertyGetDelegate(PropertyInfo);
						result = fastProperty(obj);
					}
					catch(RemotingSyncException)
					{
						throw;
					}
					catch (Exception exception)
					{
						if (after == null || !args.CanInvoke)
							throw;

						args.Exception = exception;
					}
					finally
					{
						if (args != null)
						{
							if (after != null && args.CanInvoke)
							{
								args.Value = result;
								after(this, args);
								result = args.Value;
							}

							var ex = args.Exception;
							if (ex != null)
								throw ex;
						}
					}

					return result;
				}
			);
		}
	}
}
